package com.cbarmstrong.MarketWatcher;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Logger;
import com.cbarmstrong.Finance.Data;
import com.cbarmstrong.Finance.Ticker;
import com.cbarmstrong.Finance.TradeSet;

public class CrossOverScheduler {

	private Logger logger;
	private int instanceID;
	private String stock;
	private Ticker ticker;
	
	public CrossOverScheduler(String stock) throws SQLException{
		String instance=System.getProperty("instance", "default");
		Connection connection=Data.initConnection();
		Statement statement=connection.createStatement();
		statement.execute("SELECT active FROM hosts WHERE name='"+instance+"'");
		ResultSet results=statement.getResultSet();
		if(!results.first()){ statement.execute("INSERT INTO hosts VALUES ( default , '"+instance+"' , true)"); }
		else if(results.getBoolean(1)){ logger.severe("Instance already running"); System.exit(8); }
		else{statement.execute("UPDATE hosts SET active=true WHERE name='"+instance+"'"); }
		logger=Data.getLogger("CrossOverScheduler");
		//logger.setLevel(Level.FINE);
		results=statement.executeQuery("SELECT id FROM hosts WHERE name='"+instance+"'");
		results.first();
		instanceID=results.getInt("id");
		results.close();
		connection.close();
	}
	
	/*private void scheduleSystems(int maxDepth, int batchSize, int stockID) {
		Connection connection;
		Statement statement;
		ResultSet results;
		logger.setLevel(Level.INFO);
		try {
			connection = Data.initConnection();
			connection.setAutoCommit(false);
			statement=connection.createStatement();
			
			statement.execute("SELECT COUNT(*) FROM indicators");
			results=statement.getResultSet();
			results.first();
			int max=results.getInt("count(*)");
			statement.execute("SELECT indicators FROM system WHERE stock="+stockID+" ORDER BY id DESC LIMIT 1");
			results=statement.getResultSet();
			Vector<Integer> nextSystem=new Vector<Integer>();
			if( results.first()){ 
				for(String s : results.getString("indicators").split("-")){
					nextSystem.add(new Integer(s));	
				}
			}
			results.close();
			if(nextSystem.size()==0){ nextSystem.add(1); }
			for(int j=0;j<batchSize;j++){
				logger.fine("Current system: "+Arrays.toString(nextSystem.toArray(new Integer[1])));
				nextSystem.set(0, nextSystem.get(0)+1);
				logger.fine("Updating system: "+Arrays.toString(nextSystem.toArray(new Integer[1])));
				for(int i=0;i<nextSystem.size();i++){
					if(nextSystem.get(i)>max){
						if(i==nextSystem.size()-1){
							nextSystem.set(i, 1);
							if(nextSystem.size()<maxDepth){ nextSystem.add(1); }
						} else{
							nextSystem.set(i, nextSystem.get(i+1));
							nextSystem.set(i+1, nextSystem.get(i+1)+1);
						}
					}
					logger.fine("Updating system: "+Arrays.toString(nextSystem.toArray(new Integer[1])));
				}
				String sql="";
				for(int i=0;i<nextSystem.size();i++){
					sql+=nextSystem.get(i);
					if(i<nextSystem.size()-1){ sql+="-"; }
				}
				statement.execute("SELECT id FROM system where stock="+stockID+" AND indicators='"+sql+"'");
				results=statement.getResultSet();
				if(results.first()){ 
					statement.execute("UPDATE system SET complete_time=NULL WHERE id="+results.getLong("id"));
				} else {
					statement.execute("INSERT INTO system VALUES (default, "+stockID+" , 0, 0, 0, 0, '', 0, "+instanceID+", 0, NULL, '"+sql+"' )");
				}
				results.close();
			}
			statement.execute("UNLOCK TABLES");
			connection.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}*/
	
	public void doGeneratedCross(int depth, int batchSize) throws InterruptedException, IOException, SQLException{
		Connection connection = Data.initConnection();
		Statement statement=connection.createStatement(), outerStatement=connection.createStatement();
		ResultSet results, outerResults, nestedResults;
		PreparedStatement updateResults=connection.prepareStatement("UPDATE system SET host_id=null, last_trade=?, trade_count=?, deviation=?, profit=?, ppt=?, pct=?, create_time=?, complete_time=? WHERE id=?");
		PreparedStatement scheduleNew=connection.prepareStatement("INSERT INTO system VALUES ( default , ?, ?, ?, 0, 0, 0, 0, '', 0, null, null )");
		PreparedStatement reschedule=connection.prepareStatement("UPDATE system SET host_id=?, complete_time=NULL WHERE id=?");
		PreparedStatement rescheduleID=connection.prepareStatement("select id from system where host_id is null and stock=? and complete_time is not null order by complete_time LIMIT ?");
		PreparedStatement getIndicators=connection.prepareStatement("select indicators.indicator from ( select * from system_indicators where system=? ) s, indicators where indicators.id=s.indicator");
		IndicatorProcessor cop;
		int stockID;
		long startTime, systemID, tsID;
		while(true){
			outerStatement.execute("SELECT id, name FROM stock");
			outerResults = outerStatement.getResultSet();
			while(outerResults.next()){
				stockID=outerResults.getInt("id");
				stock=outerResults.getString("name");
				if(statement.executeUpdate("UPDATE locks SET value=1 WHERE key_name='S "+stock+"' and value=0")==0){ logger.info("Scheduling skipped for "+stock); continue; }
				logger.info("Prepping schedule for "+stock);
				results=statement.executeQuery("select * from (select ifnull(max(id),0) as systems_max from systems) s, (select ifnull(max(system_id),( select ifnull(min(id),0) from systems ) ) as scheduled_max from system where stock="+stockID+") m");
				results.first();
				int i=0;
				long remainder=results.getLong(1)-results.getLong(2);
				long latestSystem=results.getLong(2);
				while(remainder>0 && i<batchSize){
					scheduleNew.setInt(1,stockID);
					scheduleNew.setLong(2,++latestSystem);
					scheduleNew.setInt(3, instanceID);
					scheduleNew.addBatch();
					remainder--;
					i++;
				}
				logger.info("Scheduling "+i+" new jobs...");
				if(i>0){ scheduleNew.executeBatch(); }
				logger.info("...complete! Scheduling existing if applicable for "+stockID);
				rescheduleID.setInt(1, stockID);
				rescheduleID.setInt(2, batchSize-i);
				results=rescheduleID.executeQuery();
				while(results.next()){
					logger.fine("Re-scheduling - Instance="+instanceID+", ID="+results.getLong(1)+", Stock="+stockID);
					reschedule.setInt(1, instanceID);
					reschedule.setLong(2, results.getLong(1));
					reschedule.addBatch();
					i++;
				}
				logger.info("Scheduling...");
				reschedule.executeBatch();
				logger.info("...complete!");
				statement.executeUpdate("UPDATE locks SET value=0 WHERE key_name='S "+stock+"'");
				logger.info("Scheduled "+i+" systems for "+stock);
				ticker=new Ticker(stock, new Integer(System.getProperty("tickerDays","800")));
				results=statement.executeQuery("SELECT id,system_id FROM system WHERE host_id="+instanceID+" AND complete_time IS NULL");
				while(results.next()){
					cop = new IndicatorProcessor();
					cop.initiate(ticker);
					systemID=results.getLong("id");
					tsID=results.getLong("system_id");
					startTime=System.currentTimeMillis();
					getIndicators.setLong(1, tsID);
					nestedResults=getIndicators.executeQuery();
					i=0;
					while(nestedResults.next()){
						String indicator=nestedResults.getString(1);
						logger.fine("Splitting "+indicator);
						cop.addCrossIndicator(indicator.split(" ")[0],indicator.split(" ")[1]);
						i++;
					}
					if(i==0){ logger.warning("No indicators for system "+systemID); }
					else{
						TradeSet ts=cop.execute();
						updateResults.setString(1, ts.getLastTrade());
						updateResults.setInt(2, ts.tradeCount());
						updateResults.setDouble(3, ts.stdDevPct());
						updateResults.setDouble(4, ts.getProfit());
						updateResults.setDouble(5, ts.pointsPerTrade());
						updateResults.setDouble(6, ts.pct(true));
						updateResults.setLong(7,startTime);
						updateResults.setLong(8, System.currentTimeMillis());
						updateResults.setLong(9, systemID);
						updateResults.addBatch();
					}
				}
				updateResults.executeBatch();
			}
		}
	}
	
}
